#include "SignalProcess.h"

//int     signo;   const char   *signame;   const char   *name;  void  (*handler)(int signo);
http_signal_t  signals[] = {
    { SIGHUP, "SIGHUP", "reload", HttpdSignalHandler },
    { SIGUSR1, "SIGUSR1","reopen", HttpdSignalHandler },
    { SIGWINCH, "SIGWINCH", "", HttpdSignalHandler },
    { SIGTERM, "SIGTERM", "stop", HttpdSignalHandler },
    { SIGQUIT, "SIGQUIT", "quit", HttpdSignalHandler },
    { SIGUSR2, "SIGUSR2", "", HttpdSignalHandler },
    { SIGALRM, "SIGALRM", "", HttpdSignalHandler },
    { SIGINT, "SIGINT", "", HttpdSignalHandler },
    { SIGIO, "SIGIO", "", HttpdSignalHandler },
    { SIGCHLD, "SIGCHLD", "", HttpdSignalHandler },
    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
    { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
    { 0, NULL, "", NULL }
};

int HttpdInitSignals()
{
    http_signal_t *sig;

    for (sig = signals; sig->signo != 0; sig++) {
        signal(sig->signo, sig->handler);
    }

    return 0;
}

int HttpdSignalProcess(http_cycle_t *cycle, char *name)
{
    http_signal_t  *sig;    
    int pid;
    std::string s;
    ReadFile(s, DAMEONPID);
    
    pid = stoi(s);
    for (sig = signals; sig->signo != 0; sig++) {
        if (strcmp(name, sig->name) == 0) {
            if (kill(pid, sig->signo) != -1) {
                llog("kill(%d, %d) ok", pid, sig->signo);
                return 0;
            }            
        }
    }

    return 1;
}

void HttpdSignalHandler(int signo)
{
    const char *action;
    int             ignore;
    http_signal_t    *sig;
    
    bzero(&action, sizeof(action));
    for (sig = signals; sig->signo != 0; sig++) {
        if (sig->signo == signo) {
            break;
        }
    }
    
    switch (signo) {

        case SIGQUIT:
            http_quit = 1;
            action = ", shutting down";
            llog("process %d recv signal SIGQUIT!", getpid());
            break;

        case SIGTERM:
        case SIGINT:
            http_terminate = 1;
            action = ", exiting";
            llog("process %d recv signal SIGTERM|SIGINT!", getpid());
            break;

        case SIGWINCH:
            http_noaccept = 1;
            action = ", stop accepting connections";
            llog("process %d recv signal SIGWINCH!", getpid());
            break;

        case SIGHUP:
            http_reconfigure = 1;
            action = ", reconfiguring";
            break;

        case SIGUSR1:
            http_reopen = 1;
            action = ", reopening logs";
            break;

        case SIGUSR2:
            if (getppid() > 1 || new_binary > 0) {
                /*
                 * Ignore the signal in the new binary if its parent is
                 * not the init process, i.e. the old binary's process
                 * is still running.  Or ignore the signal in the old binary's
                 * process if the new binary's process is already running.
                 */
                action = ", ignoring";
                ignore = 1;
                break;
            }

            http_change_binary = 1;
            action = ", changing binary";
            break;

        case SIGALRM:
            http_sigalrm = 1;
            break;

        case SIGIO:
            http_sigio = 1;
            break;

        case SIGCHLD:
            http_reap = 1;
            llog("process %d recv signal SIGCHLD!", getpid());
            break;
    }      
    
    int pid=0, status, i;
    
    if (signo == SIGCHLD) {
        for ( ; ;) {
	        pid = waitpid(-1, &status, WNOHANG);
            
	        if (pid == 0 ) {
		        return;
	        }

	        if (pid == -1) {
		        if (errno == EINTR) {
			        continue;
		        }
		        //llog("SIGCHLD loop pid:%d error:%d! http_last_process:%d", pid, errno,http_last_process);
		        return;
	        }

	        for (i=0; i<http_last_process; i++) {
		        if (http_processes[i].pid==pid) {
			        http_processes[i].status = status;
			        http_processes[i].exited = 1;
			        const char *process = http_processes[i].name;
			        break;
		        }
	        }

	        if (WEXITSTATUS(status) == 2 && http_processes[i].respawn) {
		        http_processes[i].respawn = 0;
	        }

        }
    }
    
//    llog("SIG end pid:%d!", getpid());
    
    return;
}
